// Written by HYD 2003/10/27

#define LOG_FILE	"/export/home/stock/tse/stockd.log"
#define MAX_LENGTH	1024
#define PORT		1453
#define H_SIZE		1024 * 1024 * 160
#define H_CHAN_SIZE	1024 * 1
#define KEY_TSE		1101
#define KEY_OTC		2101
#define KEY_B_TSE	5301
#define KEY_B_OTC	6301
#define KEY_CAT		1104
#define KEY_CHAN	7701

#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <sys/ipc.h>
#include "hhash.h"

void h_readline( int sockfd );
void h_watchdog( int a );

int drop_shm(key_t key);
void Create_shm( key_t key,ltick_t *cr_shm );
int Check_shm(key_t SHMKEY,int addr);
void Create_shm_chm(  );


ltick_t *ltick_tse, *ltick_otc;
struct cls
{
  struct cat
  {
    struct stock
    {
      char stockno[10];
      char stock_name[20];
    };
    int total;
    unsigned char catname[10];
    int prefix;
    int so;
    struct stock stockmem[1000];
  };
  struct cat stocktype[10][100];
}
 *cls;

typedef struct
{
  int no;
  char stockno[8], stock_name[14];
}
node;
node node2[NUM_EMPL], node3[NUM_EMPL];

#ifdef LOG
FILE *logfd;
time_t rightnow;
pthread_mutex_t locklog = { {0} };
#endif

int main( int argc, char* argv[] )
{
	ltick_t *old_tse, *old_otc;
	
	// 1:The first group to grasp the old shm ; 2: Grasping the second set of new shm
	char *chang_c;	
	int shmid_tse, shmid_otc, shmid_chan;


	if ( argc == 2){
		if( !Check_shm( KEY_CHAN, 0 ) ){
			Create_shm_chm(  );
		}else {
			shmid_chan = shmget( KEY_CHAN, 0, 0 );
			chang_c = shmat( shmid_chan, 0, 0 );
			strcpy (chang_c, "1");
			shmdt( (void *) chang_c );
		}

		if (!strcmp(argv[1], "1")){

			if ( !drop_shm( KEY_B_TSE ) ){
				printf("%s", "not drop shm form tse !!");
			}
				if( !Check_shm( KEY_TSE, 0 ) ){
					perror( "shm tse1: error" );
					return (-2);
				}
				shmid_tse = shmget( KEY_TSE, 0, 0 );
				old_tse = shmat( shmid_tse, 0, 0 );
				Create_shm( KEY_B_TSE, old_tse );
				shmdt( (void *) old_tse );

			if ( !drop_shm( KEY_B_OTC ) ){
				printf("%s", "not drop shm form tse !!");
			}
			if( !Check_shm( KEY_OTC, 0 ) ){
				perror( "shm otc1: error" );
				return (-3);
			}
			shmid_otc = shmget( KEY_OTC, 0, 0 );
			old_otc = shmat( shmid_otc, 0, 0 );
			Create_shm( KEY_B_OTC, old_otc );
			shmdt( (void *) old_otc );
			
			shmid_chan = shmget( KEY_CHAN, 0, 0 );
			chang_c = shmat( shmid_chan, 0, 0 );
			strcpy (chang_c, "2");
			shmdt( (void *) chang_c );
		}
	}
	
  		chdir( "/" );
  		umask( 0 );
  		if( getppid(  ) == 1 )
  		{
    			return 0;
  		}
  		if( fork(  ) )
  		{
    			_exit( 2 );
  		}
  		setsid(  );
  		h_watchdog( 0 );
  		return 0;
}

int h_sort_search( const void *a, const void *b )
{
  return strcmp( ( ( const node * ) a )->stockno,
                 ( ( const node * ) b )->stockno );
}

#ifdef LOG
void h_log( int sockfd, pthread_t pthreadno, char *format )
{
  static struct tm *mytm;

  if( logfd )
  {
    time( &rightnow );
    mytm = localtime( &rightnow );
    pthread_mutex_lock( &locklog );
    fprintf( logfd, "%d/%02d/%02d-%02d:%02d:%02d-%d\t%d-%s\n",
             mytm->tm_year + 1900, mytm->tm_mon + 1, mytm->tm_mday,
             mytm->tm_hour, mytm->tm_min, mytm->tm_sec, sockfd,
             ( int ) pthreadno, format );
    pthread_mutex_unlock( &locklog );
    fflush( logfd );
  }
}
#endif

void h_watchdog( int a )
{
  int shmid_tse, shmid_otc, shmid_cat, z, sockfd, addr_len, newfd, y;
  struct sockaddr_in addr;
  int shmid_chan;
  char *chang;
  key_t key_tse_i, key_otc_i;

  if( fork(  ) )
  {
    signal( SIGCHLD, h_watchdog );
    while( 1 )
    {
      sleep( 100 );
    }
  }
  else
  {
    shmid_chan = shmget( KEY_CHAN, 0, 0 );
    chang = shmat( shmid_chan, 0, 0 );
    //printf("%s\n", chang);
    if (!strcmp(chang, "1")){
    	key_tse_i = KEY_TSE;
    	key_otc_i = KEY_OTC;
    }else {
    	key_tse_i = KEY_B_TSE;
    	key_otc_i = KEY_B_OTC;
    }
    
    
    if( ( shmid_tse = shmget( key_tse_i, H_SIZE, 0 ) ) < 0 &&
       	( shmid_tse = shmget( key_tse_i, H_SIZE, IPC_CREAT | 438 ) ) < 0 )
    {
	perror( "shm tse: " );
	return;
    }
    
    if( ( ltick_tse = shmat( shmid_tse, 0, 0 ) ) == ( void * ) -1 )
    {
      perror( "shmat tse: " );
      return;
    }
    

    if( ( shmid_otc = shmget( key_otc_i, H_SIZE, 0 ) ) < 0 &&
       	( shmid_otc = shmget( key_otc_i, H_SIZE, IPC_CREAT | 438 ) ) < 0 )
    {
	perror( "shm otc: " );
	return;
    }

    if( ( ltick_otc = shmat( shmid_otc, 0, 0 ) ) == ( void * ) -1 )
    {
      perror( "shmat otc: " );
      return;
    }
    if( ( shmid_cat = shmget( KEY_CAT, 50 * 1024 * 1024, 0 ) ) < 0 &&
        ( shmid_cat =
          shmget( KEY_CAT, 50 * 1024 * 1024, IPC_CREAT | 438 ) ) < 0 )
    {
      perror( "shm cat: " );
      return;
    }
    if( ( cls = shmat( shmid_cat, 0, 0 ) ) == ( void * ) -1 )
    {
      perror( "shmat cat: " );
      return;
    }
    for( z = 0; z < NUM_EMPL; z++ )
    {
      node2[z].no = z;
      for( y = strlen( ltick_tse->DIFF_num[z].stockno ) - 1;
           ltick_tse->DIFF_num[z].stockno[y] == 32; y-- )
      {
        ltick_tse->DIFF_num[z].stockno[y] = 0;
      }
      strcpy( node2[z].stockno, ltick_tse->DIFF_num[z].stockno );
      strcpy( node2[z].stock_name, ltick_tse->DIFF_num[z].stock_name );
      node3[z].no = z;
      for( y = strlen( ltick_otc->DIFF_num[z].stockno ) - 1;
           ltick_otc->DIFF_num[z].stockno[y] == 32; y-- )
      {
        ltick_otc->DIFF_num[z].stockno[y] = 0;
      }
      strcpy( node3[z].stockno, ltick_otc->DIFF_num[z].stockno );
      strcpy( node3[z].stock_name, ltick_otc->DIFF_num[z].stock_name );
    }
    qsort( node2, NUM_EMPL, sizeof( node ), h_sort_search );
    qsort( node3, NUM_EMPL, sizeof( node ), h_sort_search );
#ifdef LOG
    logfd = fopen( LOG_FILE, "a+" );
#endif
    if( ( sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    {
      perror( "socket: " );
      return;
    }
    memset( &addr, 0, sizeof( addr ) );
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl( INADDR_ANY );
    addr.sin_port = htons( PORT );
    z = 1;
    setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, ( const void * ) &z, sizeof( z ) );
    bind( sockfd, ( struct sockaddr * ) &addr, sizeof( addr ) );
    while( listen( sockfd, 8192 ) == -1 )
    {
      sleep( 1 );
    }
    addr_len = sizeof( addr );
    while( 1 )
    {
      if( ( newfd = accept( sockfd, ( struct sockaddr * ) &addr,
                            &addr_len ) ) == -1 )
      {
        perror( "accept: " );
        continue;
      }
      pthread_create( NULL, NULL, ( void *( * )( void * ) ) h_readline,
                      (void *) newfd );
    }
    shmdt( ( void * ) cls );
    shmdt( ( void * ) ltick_otc );
    shmdt( ( void * ) ltick_tse );
    shmdt( ( void * ) chang );
  }
}

void h_funca( int sockfd, char *stockno )
{
  int y, z = 0, maxi, num = 0;
  char stocks[( maxi = strlen( stockno ) / 5 + 1 )][8], *p, temp[32],
    buf[512];

  if( ( p = strtok( stockno, " " ) ) )
  {
    strncpy( stocks[num++], p, 7 );
    while( num < maxi && ( p = strtok( NULL, " " ) ) )
    {
      strncpy( stocks[num++], p, 7 );
    }
  }
  else
  {
    strncpy( stocks[num++], stockno, 7 );
  }
  for( z = 0; z < NUM_EMPL; z++ )
  {
    for( y = 0; y < num; y++ )
    {
      if( *ltick_tse->DIFF_num[z].stockno &&
          !strncmp( ltick_tse->DIFF_num[z].stockno, stocks[y],
                    strlen( stocks[y] ) ) &&
          !ltick_tse->DIFF_num[z].stockno[strlen( stocks[y] )] )
      {
        sprintf( buf,
                 "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%f\t%ld\t%f\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n",
                 ltick_tse->date, ltick_tse->DIFF_num[z].stockno,
                 ltick_tse->DIFF_num[z].stock_name,
                 ltick_tse->DIFF_num[z].refprice,
                 ltick_tse->DIFF_num[z].dealprice,
                 ltick_tse->DIFF_num[z].pricediff,
                 ltick_tse->DIFF_num[z].dealvolume,
                 ltick_tse->DIFF_num[z].openprice,
                 ltick_tse->DIFF_num[z].maxprice,
                 ltick_tse->DIFF_num[z].minprice,
                 ltick_tse->DIFF_num[z].maximum,
                 ltick_tse->DIFF_num[z].minimum,
                 ltick_tse->DIFF_num[z].ticktime,
                 ltick_tse->DIFF_num[z].serial, ltick_tse->DIFF_num[z].diff,
                 ( long ) ltick_tse->DIFF_num[z].deal,
                 ltick_tse->DIFF_num[z].amp,
                 ltick_tse->DIFF_num[z].buyprice[0],
                 ltick_tse->DIFF_num[z].buyprice[1],
                 ltick_tse->DIFF_num[z].buyprice[2],
                 ltick_tse->DIFF_num[z].buyprice[3],
                 ltick_tse->DIFF_num[z].buyprice[4],
                 ltick_tse->DIFF_num[z].buyvolume[0],
                 ltick_tse->DIFF_num[z].buyvolume[1],
                 ltick_tse->DIFF_num[z].buyvolume[2],
                 ltick_tse->DIFF_num[z].buyvolume[3],
                 ltick_tse->DIFF_num[z].buyvolume[4],
                 ltick_tse->DIFF_num[z].sellvolume[0],
                 ltick_tse->DIFF_num[z].sellvolume[1],
                 ltick_tse->DIFF_num[z].sellvolume[2],
                 ltick_tse->DIFF_num[z].sellvolume[3],
                 ltick_tse->DIFF_num[z].sellvolume[4],
                 ltick_tse->DIFF_num[z].sellprice[0],
                 ltick_tse->DIFF_num[z].sellprice[1],
                 ltick_tse->DIFF_num[z].sellprice[2],
                 ltick_tse->DIFF_num[z].sellprice[3],
                 ltick_tse->DIFF_num[z].sellprice[4],
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].ticktime,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].serial,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].pricediff,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].buyvolume,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].sellvolume,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].buyprice,
                 ltick_tse->DIFF_num[z].LDIFF_num[ltick_tse->DIFF_num[z].num -
                                                  1].sellprice );
        if( write( sockfd, buf, strlen( buf ) ) < 0 )
        {
          close( sockfd );
        }
        stocks[y][0] = 0;
        break;
      }
    }
  }
  for( z = 0; z < NUM_EMPL; z++ )
  {
    for( y = 0; y < num; y++ )
    {
      if( *ltick_otc->DIFF_num[z].stockno &&
          !strncmp( ltick_otc->DIFF_num[z].stockno, stocks[y],
                    strlen( stocks[y] ) ) &&
          !ltick_otc->DIFF_num[z].stockno[strlen( stocks[y] )] )
      {
        sprintf( buf,
                 "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%f\t%ld\t%f\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n",
                 ltick_otc->date, ltick_otc->DIFF_num[z].stockno,
                 ltick_otc->DIFF_num[z].stock_name,
                 ltick_otc->DIFF_num[z].refprice,
                 ltick_otc->DIFF_num[z].dealprice,
                 ltick_otc->DIFF_num[z].pricediff,
                 ltick_otc->DIFF_num[z].dealvolume,
                 ltick_otc->DIFF_num[z].openprice,
                 ltick_otc->DIFF_num[z].maxprice,
                 ltick_otc->DIFF_num[z].minprice,
                 ltick_otc->DIFF_num[z].maximum,
                 ltick_otc->DIFF_num[z].minimum,
                 ltick_otc->DIFF_num[z].ticktime,
                 ltick_otc->DIFF_num[z].serial, ltick_otc->DIFF_num[z].diff,
                 ( long ) ltick_otc->DIFF_num[z].deal,
                 ltick_otc->DIFF_num[z].amp,
                 ltick_otc->DIFF_num[z].buyprice[0],
                 ltick_otc->DIFF_num[z].buyprice[1],
                 ltick_otc->DIFF_num[z].buyprice[2],
                 ltick_otc->DIFF_num[z].buyprice[3],
                 ltick_otc->DIFF_num[z].buyprice[4],
                 ltick_otc->DIFF_num[z].buyvolume[0],
                 ltick_otc->DIFF_num[z].buyvolume[1],
                 ltick_otc->DIFF_num[z].buyvolume[2],
                 ltick_otc->DIFF_num[z].buyvolume[3],
                 ltick_otc->DIFF_num[z].buyvolume[4],
                 ltick_otc->DIFF_num[z].sellvolume[0],
                 ltick_otc->DIFF_num[z].sellvolume[1],
                 ltick_otc->DIFF_num[z].sellvolume[2],
                 ltick_otc->DIFF_num[z].sellvolume[3],
                 ltick_otc->DIFF_num[z].sellvolume[4],
                 ltick_otc->DIFF_num[z].sellprice[0],
                 ltick_otc->DIFF_num[z].sellprice[1],
                 ltick_otc->DIFF_num[z].sellprice[2],
                 ltick_otc->DIFF_num[z].sellprice[3],
                 ltick_otc->DIFF_num[z].sellprice[4],
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].ticktime,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].serial,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].pricediff,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].buyvolume,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].sellvolume,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].buyprice,
                 ltick_otc->DIFF_num[z].LDIFF_num[ltick_otc->DIFF_num[z].num -
                                                  1].sellprice );
        if( write( sockfd, buf, strlen( buf ) ) < 0 )
        {
          close( sockfd );
        }
        stocks[y][0] = 0;
        break;
      }
    }
  }
  for( z = 0; z < num; z++ )
  {
    if( *stocks[z] )
    {
      sprintf( temp, "ERR stock %s not found\r\n", stocks[z] );
      if( write( sockfd, temp, strlen( temp ) ) < 0 )
      {
        close( sockfd );
        return;
      }
    }
  }
  if( write( sockfd, "--END--\r\n", 9 ) < 0 )
  {
    close( sockfd );
  }
}

void h_funcb( int sockfd, char *stockno )
{
  int z;
  char temp[128];
  node *node0, node1;

  strcpy( node1.stockno, stockno );
  if( ( node0 = bsearch( &node1, node2, sizeof( node2 ) / sizeof( node1 ),
                         sizeof( node1 ), h_sort_search ) ) )
  {
    for( z = 0; z < ltick_tse->DIFF_num[node0->no].num; z++ )
    {
      sprintf( temp, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n",
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].ticktime,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].serial,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].pricediff,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].buyvolume,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].sellvolume,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].buyprice,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].sellprice,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].dealprice,
               ltick_tse->DIFF_num[node0->no].LDIFF_num[z].dealvolume );
      if( write( sockfd, temp, strlen( temp ) ) < 0 )
      {
        close( sockfd );
        return;
      }
    }
    if( write( sockfd, "--END--\r\n", 9 ) < 0 )
    {
      close( sockfd );
    }
    return;
  }
  if( ( node0 = bsearch( &node1, node3, sizeof( node3 ) / sizeof( node1 ),
                         sizeof( node1 ), h_sort_search ) ) )
  {
    for( z = 0; z < ltick_otc->DIFF_num[node0->no].num; z++ )
    {
      sprintf( temp, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n",
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].ticktime,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].serial,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].pricediff,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].buyvolume,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].sellvolume,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].buyprice,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].sellprice,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].dealprice,
               ltick_otc->DIFF_num[node0->no].LDIFF_num[z].dealvolume );
      if( write( sockfd, temp, strlen( temp ) ) < 0 )
      {
        close( sockfd );
        return;
      }
    }
    if( write( sockfd, "--END--\r\n", 9 ) < 0 )
    {
      close( sockfd );
    }
    return;
  }
  if( write( sockfd, "ERR stock not found\r\n", 21 ) < 0 )
  {
    close( sockfd );
  }
}

void h_funcc( int sockfd, char *stockno )
{
  char *stype, *category, temp[64];
  int nstype, ncategory, z;

  if( !( stype = strtok( stockno, " " ) )
      || !( category = strtok( NULL, " " ) ) )
  {
    if( write( sockfd, "ERR cmd\r\n", 9 ) < 0 )
    {
      close( sockfd );
    }
    return;
  }
  nstype = atoi( stype );
  ncategory = atoi( category );
  for( z = 0; z < cls->stocktype[nstype][ncategory].total; z++ )
  {
    sprintf( temp, "%s\t%s\r\n",
             cls->stocktype[nstype][ncategory].stockmem[z].stockno,
             cls->stocktype[nstype][ncategory].stockmem[z].stock_name );
    if( write( sockfd, temp, strlen( temp ) ) < 0 )
    {
      close( sockfd );
      return;
    }
  }
  if( write( sockfd, "--END--\r\n", 9 ) < 0 )
  {
    close( sockfd );
  }
}

void h_readline( int sockfd )
{
  int z;
  char string[MAX_LENGTH];
  static struct getfunc
  {
    void ( *p ) ( int, char * );
  }
  get_func[] =
  {
    {
    h_funca},
    {
    h_funcb},
    {
    h_funcc}
  };

  while( 1 )
  {
    if( ( z = read( sockfd, string, sizeof( string ) ) ) <= 0 )
    {
      close( sockfd );
      pthread_detach( pthread_self(  ) );
      pthread_exit( ( void * ) 0 );
    }
    string[strlen( string ) - 2] = 0;
    string[strlen( string )] = 0;
    string[strlen( string ) + 1] = 0;
    string[z] = 0;
#ifdef LOG
    h_log( sockfd, pthread_self(  ), string );
#endif
    if( !strncasecmp( string, "GET", 3 ) && string[3] > 64 && string[3] < 68 )
    {
      ( void ) ( get_func[string[3] - 65].p ) ( sockfd, string + 5 );
    }
    else
    {
      write( sockfd, "ERR cmd\r\n", 9 );
      close( sockfd );
      pthread_detach( pthread_self(  ) );
      pthread_exit( ( void * ) 0 );
      return;
    }
  }
}


int Check_shm(key_t SHMKEY,int addr)
{
   if (shmget(SHMKEY,addr,0)== -1)
        return (0);

   return (1);
}

int drop_shm(key_t key)
{
  int shmid;
  shmid = shmget( key, H_SIZE ,0 );
  if (shmctl(shmid, IPC_RMID, NULL) == -1){
    return 0;
  }else{
    return 1;}
}

void Create_shm( key_t key, ltick_t *cr_shm ){
        ltick_t *shm;
        int shmid;
        shmid = shmget( key,H_SIZE,IPC_CREAT| 0666 );
        shm = shmat( shmid, 0, 0 );
//        strcpy( shm, "" );
        memcpy( shm, cr_shm, H_SIZE );
        //strcat(shm,cr_shm);
        shmdt( (void *) shm );
}

void Create_shm_chm(  ){
        char *shm;
        int shmid;
        shmid = shmget( KEY_CHAN, H_CHAN_SIZE ,IPC_CREAT| 0666 );
        shm = shmat( shmid, 0, 0 );

        strcpy( shm, "1" );

        shmdt( (void *) shm );
}
